﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;

namespace MassCoverDownloader
{
    public class CoreDownloader
    {
        public CoreDownloader(string path, bool overwrite = false)
        {
            rootPath = path;
            overWrite = overwrite;
            currIdx = 0;
            notFoundErrors = 0;
            connectionErrors = 0;
            priviledgeErrors = 0;
            log = rootPath + Path.DirectorySeparatorChar + "log.txt";
            prepareLog();
            Count();
        }

        public int getCount()
        {
            return dirCount;
        }

        private void prepareLog()
        {
            try
            {
                if (File.Exists(log))
                {
                    File.Delete(log);
                }
                FileInfo f = new FileInfo(log);
                sw = f.CreateText();
                sw.WriteLine("Log Created at " + DateTime.Now);       
            }
            catch (Exception)
            {
                throw new Exception("Cannot create log file!");
                throw;
            }
        }

        public void closeLog()
        {
            sw.Close();    
        }

        private void logMsg(string msg)
        {
            try
            {
                sw.WriteLine(msg);
            }
            catch (Exception)
            {
                throw new Exception("Unable to write to log!");
                throw;
            }
        }

        private void Count()
        {
            DirectoryInfo di = new DirectoryInfo(rootPath);
            DirectoryInfo[] sub = di.GetDirectories();
            dirCount = sub.Length;
            subDirs = new string[dirCount];            

            logMsg("root path : " + rootPath);
            logMsg("elements to process : " + dirCount);

            for(int i=0; i<dirCount; ++i)
            {
                subDirs[i] = sub[i].FullName;
                logMsg(subDirs[i]);
            }            
        }

        public string next()
        {
            string input;
            string output;
            bool succ = false;

            if (currIdx < dirCount)
            {
                input = subDirs[currIdx];
                logMsg(">> processing : " + currIdx + " element");
                logMsg(">> >> " + input);
                //
                // Process one cover and return path to saved image
                if (input.Length == 0)
                {
                    logMsg("!! Error: input name empty or too short!");
                    return "Argument error";
                    //throw new ArgumentException("Input string is empty or too short!");
                }
                else
                {
                    // Preprocess dir name
                    string valid = splitClean(input);
                    logMsg(">> search key : " + valid);
                    StringBuilder sb = new StringBuilder();
                    sb.Append(@"http://www.google.pl/images?um=1&hl=pl&gbv=2&tbs=isch%3A1%2Citp%3Aphoto%2Cisz%3Alt%2Cislt%3Aqsvga&sa=1&q=");
                    sb.Append(valid);
                    sb.Append(@"&btnG=Szukaj&aq=f&aqi=&aql=&oq=");

                    // Query google images page
                    string text;
                    try
                    {
                        WebClient cl = new WebClient();
                        IWebProxy myProxy = GlobalProxySelection.GetEmptyWebProxy();
                        cl.Proxy = myProxy;
                        text = cl.DownloadString(sb.ToString());
                        logMsg(">> successfully downloaded results page");
                    }
                    catch (Exception e)
                    {
                        //System.Windows.Forms.MessageBox.Show("Error while connecting. Check your internet connection!", "Error");
                        connectionErrors++;
                        logMsg("!! Error: Connection error");
                        return "Connection error";
                    }

                    // Retrieve first image from results
                    {
                        int stIdx = text.IndexOf("setResults([[");
                        if (stIdx == -1)
                        {
                            // Cover not found :(
                            logMsg("!! Error: cover not found");
                            notFoundErrors++;
                            return "Cover Not Found!";
                        }
                        String choped = text.Substring(stIdx);
                        int httpIdx = choped.IndexOf("http");
                        string c1 = choped.Substring(httpIdx);
                        int x26Idx = c1.IndexOf("\\x26");
                        string c2 = c1.Remove(x26Idx);
                        try
                        {
                            downloadImage(c2, input + Path.DirectorySeparatorChar + "Cover.jpg");
                            output = input + Path.DirectorySeparatorChar + "Cover.jpg";
                            succ = true;
                            logMsg(">> Success download cover to " + output);
                        }
                        catch (Exception)
                        {
                            logMsg("!! Error: unable to download cover. Permission issue");
                            priviledgeErrors++;
                            return "Permission error";
                        }
                    }
                }
                // 
                currIdx++;
                if (succ)
                    return output;
                else
                    return "Unknown Error occurred";
            }
            else
            {
                return "No more elements to process";
            }
        }

        public string generateReport()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("Job Raport: \n");
            sb.Append("Selected directory: \n");
            sb.Append(rootPath);
            sb.Append("\nhas ");
            sb.Append(dirCount);
            sb.Append(" subfolders.\n");
            sb.Append((dirCount-connectionErrors-priviledgeErrors-notFoundErrors));
            sb.Append(" of these, where processed successfully.\n");
            sb.Append("There were " + connectionErrors + " connection errors.");
            sb.Append("\n" + priviledgeErrors + " permission errors.");
            sb.Append("\n" + notFoundErrors + " not found cover errors.");
            sb.Append("\nSee log.txt for futher details");
            logMsg("----- Report generated. End of log.");                    
            return sb.ToString();
        }

        private string splitClean(string input)
        {
            DirectoryInfo di = new DirectoryInfo(input);
            // Gets Directorys Name
            string t1 = di.Name;

            // Cleans non alphanumeric characters            
            string pattern = @"[^a-zA-Z0-9\s]";
            string replacement = " ";
            Regex rgx = new Regex(pattern);
            string t2 = rgx.Replace(t1, replacement);

            // Trim multiple whitespaces
            string pattern2 = "\\s+";
            string replacement2 = "+";
            Regex rgx2 = new Regex(pattern2);
            string t3 = rgx2.Replace(t2, replacement2);           
            return t3.Trim();
        }

        private void downloadImage(string url, string fileName)
        {
            // Create an instance of WebClient
            WebClient client = new WebClient();
            client.Proxy = null;
            if (File.Exists(fileName) && overWrite)
            {
                File.Delete(fileName);
            }

            try
            {
                client.DownloadFile(new Uri(url), fileName);
            }
            catch (Exception e)
            {
                priviledgeErrors++;
                throw;
            }
        }

        private bool overWrite;
        private int notFoundErrors;
        private int connectionErrors;
        private int priviledgeErrors;
        private int currIdx;
        private int dirCount;
        private string rootPath;
        private string[] subDirs;
        private string log;
        private StreamWriter sw;

    }
}
